package com.yyx.jupiter.service.recommend.recall;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.yyx.jupiter.conf.PropertyConfig;
import com.yyx.jupiter.entity.RecomReq;
import com.yyx.jupiter.entity.RecomVideo;
import com.yyx.jupiter.component.CacheManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.cloud.context.config.annotation.RefreshScope;

import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;


@Slf4j
@Service
@RefreshScope
public class HotRecall implements Recallable<RecomVideo> {

    @Resource
    CacheManager cacheUtils;

    @Resource
    PropertyConfig propertyConfig;

    @Override
    public List<RecomVideo> recall(RecomReq recomReq) throws Exception {

        long startTime = System.currentTimeMillis();

        // 请求体参数
        String sceneId = recomReq.getSceneId();
        String strategy = recomReq.getStrategy();
        String redisKey = String.format("yyx:hotrecall:%s", sceneId);

        // 配置参数
        JSONObject strategyJson = propertyConfig.getStrategy().getJSONObject(strategy);
        JSONObject hotJson = strategyJson.getJSONObject("recallLayer").getJSONObject("hot");
        boolean logPrintSwitch = MapUtils.getBooleanValue(strategyJson, "logPrintSwitch", false);

        if (!hotJson.containsKey("recallNum")) {
            log.error("{}没有recallNum参数", this.getClass().getSimpleName());
        }

        // 获取redis数据
        Object redisObj = cacheUtils.getHotRecallCache(redisKey);
        if (redisObj == null) {
            return new ArrayList<>();
        }

        // 反射解析
        List<RecomVideo> recomList = JSON.parseArray(redisObj.toString(), RecomVideo.class);

        // 截断召回数量
        int recallNum = hotJson.getIntValue("recallNum");
        recomList = recomList.stream()
                .sorted(Comparator.comparingDouble(RecomVideo::getScore).reversed())
                .limit(recallNum).collect(Collectors.toList());

        // 塞入召回类型
        for (RecomVideo hotRecomVideo : recomList) {
            hotRecomVideo.setRecallStrategy("hot");
        }

        if (logPrintSwitch) {
            log.info("requestId:{}, hot recall process elapsed: {} ms, com.yyx.jupiter.recall size: {}",
                    recomReq.getRequestId(), (System.currentTimeMillis() - startTime), recomList.size());
        }
        return recomList;
    }
}
